home *** CD-ROM | disk | FTP | other *** search
- //=====================================================================
- //
- // dpmirun.cpp
- //
- // This is the loader for protected mode dos applications.
- //
- // This is very dependant on Borland C++.
- // It must be compiled in small model.
- //
- // It requires DPMI to work.
- //
- // Copyright (c) 1994, Kevin Morgan, All rights reserved.
- //
- //=====================================================================
-
- #define GLOBALS
- #include "dpmirun.h"
-
- //=====================================================================
- //
- // GpfRegs
- //
- // This is what our stack looks like after we have entered our
- // exception handler.
- //
- // This is heavily dependant on order that Borland C pushes
- // registers onto the stack.
- //
- //=====================================================================
- struct GpfRegs {
- WORD Rbp;
- WORD Rdi;
- WORD Rsi;
- WORD Rds;
- WORD Res;
- WORD Rdx;
- WORD Rcx;
- WORD Rbx;
- WORD Rax;
- WORD Rip;
- WORD Rcs;
- WORD Rfl;
- WORD faultip;
- WORD faultcs;
- WORD flags;
- WORD sp;
- WORD ss;
- };
-
-
- //=====================================================================
- //
- // global variables
- //
- //=====================================================================
-
-
- jmp_buf trapbuf; // for a long jump to our exception handler
-
- GpfRegs gpfRegs; // registers at the time of the exception
-
-
- //=====================================================================
- //
- // printDpmiException
- //
- // print out our machine state, and attempt to do a traceback
- //
- //=====================================================================
- void printDpmiException(ModuleLoader *module)
- {
- int i;
- GpfRegs * pGpfRegs = &gpfRegs;
-
- printf("\nProcessor Exception:\n");
- printf("CS=%04x, DS=%04x SS:SP=%04x:%04x\n", _CS, _DS, _SS, _SP);
-
- printf("bp=%04x, di=%04x, si=%04x ds=%04x\n",
- pGpfRegs->Rbp,
- pGpfRegs->Rdi,
- pGpfRegs->Rsi,
- pGpfRegs->Rds);
- printf("es=%04x, dx=%04x, cx=%04x bx=%04x\n",
- pGpfRegs->Res,
- pGpfRegs->Rdx,
- pGpfRegs->Rcx,
- pGpfRegs->Rbx);
- printf("ax=%04x, ip=%04x, cs=%04x fl=%04x\n",
- pGpfRegs->Rax,
- pGpfRegs->Rip,
- pGpfRegs->Rcs,
- pGpfRegs->Rfl);
-
- printf("Fault CS:IP = %04x:%04x Flags=%04x\n",
- pGpfRegs->faultcs,
- pGpfRegs->faultip,
- pGpfRegs->flags);
-
- printf("ss:sp = %04x:%04x\n",
- pGpfRegs->ss,
- pGpfRegs->sp);
-
- jmp_buf savetrap;
- memcpy(savetrap, trapbuf, sizeof(jmp_buf));
-
- if (setjmp(trapbuf)==0) { // a fault here is ok
- printf("\nStack traceback follows:\n");
- {
- char *faultDescr = module->describeFaultPc(
- pGpfRegs->faultcs, pGpfRegs->faultip);
- printf("Fault at %s\n", faultDescr);
- }
- unsigned bp = pGpfRegs->Rbp;
- for (i=0;i<20;i++) {
- unsigned far *p = (unsigned far *) MK_FP(pGpfRegs->ss, bp);
- char *faultDescr = module->describeFaultPc(
- p[2], p[1]);
- printf("call from %s\n", faultDescr);
- if (p[0]<=bp) break;
- if (p[0]==0xffff) break;
- bp = p[0];
- }
- }
- memcpy(trapbuf, savetrap, sizeof(jmp_buf));
- }
-
-
- //=====================================================================
- //
- // installExceptionHandler
- //
- // Install an exception handler to handle all protected mode processor
- // exceptions.
- //
- //=====================================================================
- void installExceptionHandler(DpmiInterruptVector v)
- {
- memset(&gpfRegs, 0, sizeof(gpfRegs));
- FP_SEG(v) = _CS;
- int i;
- for (i=0;i<32;i++)
- Dpmi.setExceptionHandler(i, v);
- /*
- Dpmi.setExceptionHandler( 0, v);
- Dpmi.setExceptionHandler( 6, v);
- Dpmi.setExceptionHandler( 7, v);
- Dpmi.setExceptionHandler( 9, v);
- Dpmi.setExceptionHandler(12, v);
- Dpmi.setExceptionHandler(13, v);
- */
- // dprintf("exception handler traps set\n");
- }
-
- //=====================================================================
- //
- // patchExceptionHandler
- //
- // Before we can install a protected mode interrupt handler, we
- // need to modify the interrupt procedure's prolog, because of
- // the way BorlandC generates code...
- //
- // This is very specific to this implementation
- // and very easy to break!
- //
- // In the prolog for Borland C interrupt procedures contains
- // code to push the registers, and load DS with DGROUP.
- //
- // ...
- // MOV AX, DGROUP
- // MOV DS, AX
- // ...
- //
- // The problem is that this is compiled in with the
- // DGROUP value of our real mode data segment.
- //
- // Since this is a protected mode interrupt handler,
- // we need that to be the protected mode selector
- // for our data segment (not known till run time).
- //
- // So we actually modify our code at run time to
- // have the right value.
- //
- // To accomplish this, we create a writeable alias selector,
- // modify the code, and get rid of the alias.
- //
- //=====================================================================
- void patchExceptionHandler(DpmiInterruptVector v)
- {
- unsigned WriteableCS;
- unsigned far *p = (unsigned far *) v;
-
- if (Dpmi.createAlias(_CS, WriteableCS)!=DPMI_OK) {
- printf("patchExceptionHandler: cannot create CS alias\n");
- return;
- }
-
- FP_SEG(p) = WriteableCS;
- p[5] = _DS;
- Dpmi.freeSelector(WriteableCS);
- }
-
- //=====================================================================
- //
- // copyArgs
- //
- // copy the argv and envp arrays. Mainly needed because we need to
- // convert from an array of near pointers to an array of far pointers.
- //
- //=====================================================================
- char far * far * copyArgs(int num, char **argv)
- {
- if (num==0) {
- char **p = argv;
- while (*p++) num++;
- }
- char far * far * table = new char far * [num+1];
- int i;
- for (i=0;i<num;i++)
- table[i] = argv[i];
- table[num] = 0;
- return table;
- }
-
- //=====================================================================
- //
- // ctrl_c
- //
- // This is a routine to catch Control-C interrupts
- //
- //
- //=====================================================================
- void far interrupt ctrl_c(...)
- {
- GpfRegs far * pGpfRegs = (GpfRegs far *) MK_FP(_SS, _BP);
- _fmemcpy( &gpfRegs, pGpfRegs, sizeof(gpfRegs) );
- longjmp(trapbuf,2);
- }
-
- //=====================================================================
- //
- // dpmiException
- //
- // This is a routine to catch protected mode processor exceptions.
- //
- //
- //=====================================================================
- void far interrupt dpmiException(...)
- {
- GpfRegs far * pGpfRegs = (GpfRegs far *) MK_FP(_SS, _BP);
- _fmemcpy( &gpfRegs, pGpfRegs, sizeof(gpfRegs) );
- longjmp(trapbuf,1);
- }
-
- //=====================================================================
- //
- // callMain
- //
- // Start executing the program we just loaded.
- //
- // We allocate a protected mode stack for the new program,
- // copy argument and environment variables, switch to the
- // new stack, and call the program's entrypoint passing
- // argc, argv, and envp.
- //
- //=====================================================================
- void callMain(ModuleLoader *module, void far *startCsIp, int argc, char **argv, char **envp)
- {
- const int StackSize = 4096;
- static char far *stk = (char far *) module->getStack(StackSize);
- if (!stk) {
- Dpmi.fail("cannot allocate protected mode stack\n");
- return;
- }
-
- stk += (StackSize-32);
-
- static int (_far *mainline)(int, char far * far *, char far * far *);
- mainline = ( int (_far *)(int, char far * far *, char far * far *) ) startCsIp;
-
- static char far* far* newargv = copyArgs(argc, argv);
-
- static char far* far* newenvp = copyArgs(0, envp);
-
- static int newargc = argc;
-
- // switch stacks
- asm {
- mov ax, word ptr stk
- mov bx, word ptr stk+2
- mov ss,bx
- mov sp,ax
- push ds
- }
-
- (*mainline)(newargc,newargv,newenvp);
-
- asm {
- pop ds
- }
- longjmp(trapbuf,3);
- }
-
-
- //=====================================================================
- //
- // protectedMain
- //
- // This is the protected mode mainline.
- // We set up exception handler, load the program and run it.
- //=====================================================================
- int protectedMain(int argc, char *argv[], char *envp[])
- {
- if (argc<2) {
- printf("usage: dpmirun filename ...\n");
- Dpmi.dosExit(1);
- }
-
- ModuleLoader *module = newModuleLoader();
-
- static char *where;
-
- where = "before execution\n";
- if (setjmp(trapbuf)!=0) {
- puts(where);
- Dpmi.fail("Exception encountered before execution\n");
- }
-
- patchExceptionHandler( ctrl_c );
- Dpmi.setProtVect(0x23, ctrl_c); // install ctrl_c handler
-
- where = "patch exception handler";
- patchExceptionHandler( dpmiException);
-
- where = "setup exception handler";
- installExceptionHandler(dpmiException);
-
- where = "error loading executable";
- module->loadExecutable(argv[1]);
-
- where = "error adjusting selectors";
- module->adjustSelectors();
-
- where = "error getting entry point";
- void _far *entryPoint = module->entryPoint();
-
- where = "error check loadErrors";
- if (module->loadErrors()) {
- printf("cannot execute because of load errors\n");
- return 0;
- }
-
- where = "reset traps";
- switch (setjmp(trapbuf)) {
- case 0:
- {
- flushall();
-
- // strip off the loader's name
- argc--;
- argv++;
- callMain(module, entryPoint, argc, argv, envp);
- break;
- }
- case 1:
- {
- if (setjmp(trapbuf)==0) {
- printDpmiException(module);
- }
- Dpmi.fail("Processor Exception encountered\n");
- break;
- }
- case 2:
- {
- Dpmi.fail("Control-C intercepted\n");
- break;
- }
-
- default:
- break;
- }
- return 0;
- }
-
-
-
- //=====================================================================
- //
- // main
- //
- // We switch to protected mode, and call the protected mode mainline
- //
- //=====================================================================
- int main(int argc, char *argv[], char *envp[])
- {
- int ret;
-
- flushall(); // flush all buffers before switch into protected mode,
- // so I/O redirection works properly
-
- if (!Dpmi.present())
- if (!Dpmi.init())
- Dpmi.fail("This program requires DPMI");
-
- // now in protected mode: segment registers have changed
-
-
- ret = protectedMain(argc, argv, envp);
-
- flushall();
-
- Dpmi.dosExit(ret);
-
- return 0;
- }
-